package com.gzc.just.play.last.war.sceneserver.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * 缓存服务类
 * 
 * 提供通用的缓存操作方法，用于优化数据库查询性能
 * 作为Phase 4.3数据库持久化集成的一部分
 */
@Service
@ConditionalOnClass(RedisConnectionFactory.class)
@ConditionalOnBean(RedisTemplate.class)
@ConditionalOnProperty(name = "allinone.enable-redis", havingValue = "true", matchIfMissing = true)
public class CacheService {
    
    private static final Logger logger = LoggerFactory.getLogger(CacheService.class);
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    // 默认缓存时间（秒）
    private static final long DEFAULT_CACHE_TIME = 300; // 5分钟
    
    // 缓存键前缀
    private static final String CACHE_PREFIX = "lastwar:";
    private static final String PLAYER_PREFIX = CACHE_PREFIX + "player:";
    private static final String PLAYER_ATTRIBUTES_PREFIX = CACHE_PREFIX + "player_attr:";
    private static final String TEAM_PREFIX = CACHE_PREFIX + "team:";
    private static final String BATTLE_PREFIX = CACHE_PREFIX + "battle:";
    private static final String LEADERBOARD_PREFIX = CACHE_PREFIX + "leaderboard:";
    
    /**
     * 获取缓存值
     */
    public <T> T get(String key, Class<T> clazz) {
        try {
            Object value = redisTemplate.opsForValue().get(key);
            if (value != null) {
                if (value.getClass() == clazz) {
                    return clazz.cast(value);
                } else if (value instanceof String) {
                    return objectMapper.readValue((String) value, clazz);
                }
            }
            return null;
        } catch (Exception e) {
            logger.error("Failed to get cache: key={}, clazz={}", key, clazz.getName(), e);
            return null;
        }
    }
    
    /**
     * 设置缓存值
     */
    public void set(String key, Object value) {
        set(key, value, DEFAULT_CACHE_TIME);
    }
    
    /**
     * 设置缓存值（带过期时间）
     */
    public void set(String key, Object value, long timeout, TimeUnit timeUnit) {
        try {
            String jsonValue;
            if (value instanceof String) {
                jsonValue = (String) value;
            } else {
                jsonValue = objectMapper.writeValueAsString(value);
            }
            redisTemplate.opsForValue().set(key, jsonValue, timeout, timeUnit);
        } catch (JsonProcessingException e) {
            logger.error("Failed to serialize cache value: key={}, value={}", key, value, e);
        } catch (Exception e) {
            logger.error("Failed to set cache: key={}, value={}", key, value, e);
        }
    }
    
    /**
     * 设置缓存值（带超时时间，单位：秒）
     */
    public void set(String key, Object value, long timeoutSeconds) {
        set(key, value, timeoutSeconds, TimeUnit.SECONDS);
    }
    
    /**
     * 删除缓存
     */
    public void delete(String key) {
        try {
            redisTemplate.delete(key);
        } catch (Exception e) {
            logger.error("Failed to delete cache: key={}", key, e);
        }
    }
    
    /**
     * 批量删除缓存
     */
    public void delete(Collection<String> keys) {
        try {
            redisTemplate.delete(keys);
        } catch (Exception e) {
            logger.error("Failed to batch delete cache: keys={}", keys, e);
        }
    }
    
    /**
     * 删除匹配模式的缓存
     */
    public void deleteByPattern(String pattern) {
        try {
            Set<String> keys = redisTemplate.keys(pattern);
            if (keys != null && !keys.isEmpty()) {
                redisTemplate.delete(keys);
            }
        } catch (Exception e) {
            logger.error("Failed to delete cache by pattern: pattern={}", pattern, e);
        }
    }
    
    /**
     * 检查缓存是否存在
     */
    public boolean exists(String key) {
        try {
            return Boolean.TRUE.equals(redisTemplate.hasKey(key));
        } catch (Exception e) {
            logger.error("Failed to check cache existence: key={}", key, e);
            return false;
        }
    }
    
    /**
     * 获取或设置缓存（使用Supplier）
     */
    public <T> T getOrSet(String key, Supplier<T> supplier, Class<T> clazz) {
        return getOrSet(key, supplier, clazz, DEFAULT_CACHE_TIME);
    }
    
    /**
     * 获取或设置缓存（使用Supplier，带过期时间）
     */
    public <T> T getOrSet(String key, Supplier<T> supplier, Class<T> clazz, long timeoutSeconds) {
        T value = get(key, clazz);
        if (value == null) {
            value = supplier.get();
            if (value != null) {
                set(key, value, timeoutSeconds);
            }
        }
        return value;
    }
    
    /**
     * 异步设置缓存
     */
    @Async("cacheUpdateExecutor")
    public void setAsync(String key, Object value) {
        set(key, value);
    }
    
    /**
     * 异步设置缓存（带过期时间）
     */
    @Async("cacheUpdateExecutor")
    public void setAsync(String key, Object value, long timeoutSeconds) {
        set(key, value, timeoutSeconds);
    }
    
    /**
     * 异步删除缓存
     */
    @Async("cacheUpdateExecutor")
    public void deleteAsync(String key) {
        delete(key);
    }
    
    /**
     * 异步批量删除缓存
     */
    @Async("cacheUpdateExecutor")
    public void deleteAsync(Collection<String> keys) {
        delete(keys);
    }
    
    /**
     * 获取玩家缓存键
     */
    public String getPlayerCacheKey(Long playerId) {
        return PLAYER_PREFIX + playerId;
    }
    
    /**
     * 获取玩家属性缓存键
     */
    public String getPlayerAttributesCacheKey(Long playerId) {
        return PLAYER_ATTRIBUTES_PREFIX + playerId;
    }
    
    /**
     * 获取队伍缓存键
     */
    public String getTeamCacheKey(Long teamId) {
        return TEAM_PREFIX + teamId;
    }
    
    /**
     * 获取战斗缓存键
     */
    public String getBattleCacheKey(Long battleId) {
        return BATTLE_PREFIX + battleId;
    }
    
    /**
     * 获取排行榜缓存键
     */
    public String getLeaderboardCacheKey(String type) {
        return LEADERBOARD_PREFIX + type;
    }
    
    /**
     * 清除所有玩家相关缓存
     */
    public void clearPlayerCache(Long playerId) {
        delete(getPlayerCacheKey(playerId));
        delete(getPlayerAttributesCacheKey(playerId));
        deleteByPattern(PLAYER_ATTRIBUTES_PREFIX + playerId + "-*");
    }
    
    /**
     * 清除所有队伍相关缓存
     */
    public void clearTeamCache(Long teamId) {
        delete(getTeamCacheKey(teamId));
        deleteByPattern(TEAM_PREFIX + teamId + "-*");
    }
    
    /**
     * 清除所有战斗相关缓存
     */
    public void clearBattleCache(Long battleId) {
        delete(getBattleCacheKey(battleId));
        deleteByPattern(BATTLE_PREFIX + battleId + "-*");
    }
    
    /**
     * 刷新排行榜缓存
     */
    @Async("cacheUpdateExecutor")
    public void refreshLeaderboard(String type, Supplier<Object> dataSupplier) {
        String key = getLeaderboardCacheKey(type);
        Object data = dataSupplier.get();
        if (data != null) {
            set(key, data, 600); // 排行榜缓存10分钟
        }
    }
    
    /**
     * 批量获取缓存
     */
    public <T> Map<String, T> multiGet(Collection<String> keys, Class<T> clazz) {
        try {
            List<Object> values = redisTemplate.opsForValue().multiGet(keys);
            Map<String, T> result = new java.util.HashMap<>();
            
            if (values != null) {
                int index = 0;
                for (String key : keys) {
                    Object value = values.get(index++);
                    if (value != null) {
                        if (value.getClass() == clazz) {
                            result.put(key, clazz.cast(value));
                        } else if (value instanceof String) {
                            result.put(key, objectMapper.readValue((String) value, clazz));
                        }
                    }
                }
            }
            
            return result;
        } catch (Exception e) {
            logger.error("Failed to batch get cache: keys={}", keys, e);
            return java.util.Collections.emptyMap();
        }
    }
    
    /**
     * 原子递增
     */
    public Long increment(String key) {
        return redisTemplate.opsForValue().increment(key);
    }
    
    /**
     * 原子递增（指定增量）
     */
    public Long increment(String key, long delta) {
        return redisTemplate.opsForValue().increment(key, delta);
    }
    
    /**
     * 原子递减
     */
    public Long decrement(String key) {
        return redisTemplate.opsForValue().decrement(key);
    }
    
    /**
     * 原子递减（指定增量）
     */
    public Long decrement(String key, long delta) {
        return redisTemplate.opsForValue().decrement(key, delta);
    }
}